package com.asmember;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.apache.http.client.ClientProtocolException;

import com.asmember.model.ASN;
import com.asmember.model.IP;
import com.asmember.model.Search;


/**
 * @author Grzegorz Matyszczak<BR>
 * @author Maciej Mastalerz	
 */
public class Main {

	
	private static final int THREADS_MAX_NUMBER = 200;
    
	
	
	public static void main(String[] args) {

		
		if(args.length<2){
			System.err.println("Za malo parametrow wywolania");
			System.exit(-1);
		}
		
		else{
			
			String AS_NUMBER = args[0];
		
			List<String> ports = new ArrayList<String>();
			for(int i=1; i<args.length; i++)
				ports.add(args[i]);
		
			long timestamp = System.currentTimeMillis();
		
			//get IP ranges for given ASN in json
			String json = RIPERequestHelper.makeRequest(AS_NUMBER);		

			if(json != null) {
			
				//parsing json to get list of IP ranges
				List<String> subnets = Parser.parseJSON(json);
			
				//getting all reachable hosts from subnets by using nmap
				Set<String> reachableHosts = new HashSet<String>();
				for(String subnet : subnets)
					reachableHosts.addAll(NmapHelper.getReachableHosts(subnet));
			
				
				//checking which ports are opened in all hosts
	        
				Map<String, List<String>> connectedHosts = new HashMap<String, List<String>>();
				for(int i=0; i<ports.size(); i++)
					connectedHosts.put(ports.get(i), Collections.synchronizedList(new ArrayList<String>()));

				ExecutorService executor = newFixedThreadPool(THREADS_MAX_NUMBER);

				for(String ip: reachableHosts)
					executor.execute( new SocketRequest(ip, connectedHosts, ports));
            
				executor.shutdown();
	        
				while (!executor.isTerminated()) {
				}
	        			
				
				float time = ((float)(System.currentTimeMillis()-timestamp))/1000;
	       
	        
				//store results to remote database
				DBHelper helper = new DBHelper();
				ASN asn = new ASN(AS_NUMBER);
				List<IP> ipList = new ArrayList<>();
				
				for(String port: ports){
					List<String> ipsByPort = connectedHosts.get(port);
					for(String ip : ipsByPort)
						ipList.add(new IP(ip, asn));
				}
				
				System.out.println("Writing results to database");
				Search search = new Search(asn, ""+time, ipList);
				helper.insertSearch(search);
				helper.insertConnectionIp(connectedHosts, ports, search);
				System.out.println("Results stored in database.");
				
				//save results in csv file
				System.out.println("Saving results to csv file");
				Calendar calendar = Calendar.getInstance();
				
				PrintWriter writer;
				try {
					writer = new PrintWriter(calendar.get(Calendar.DAY_OF_MONTH)+"-"+calendar.get(Calendar.MONTH)+"-"+calendar.get(Calendar.YEAR)+"-"+calendar.get(Calendar.HOUR_OF_DAY)+"-"+calendar.get(Calendar.MINUTE)+".csv");
					writer.println("ip;port");
					
					for(String port: ports){
						List<String> ipsByPort = connectedHosts.get(port);
						for(String ip : ipsByPort)
							writer.println(ip+";"+port);
					}
		      	  	writer.close();
					System.out.println("Results stored in csv file");
				} catch (FileNotFoundException e) {
			
				}
	      	  	
	      	  	
	      	  	
		}
		}
	}
	
	
	public static ExecutorService newFixedThreadPool (int threads) {
        return new ThreadPoolExecutor(threads, threads,
                0L, TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>());
    }
	
}
